<h4>投资情绪的测量</h4>
<p>
  要衡量投资者的情绪，我们使用的指标是：芝加哥期权交易所(CBOE)的股票看跌/看涨比率和市场波动率(VIX)指数。VIX指数是利用标准普尔500指数期权的隐含波动率构建的，它显示了市场对30天波动率的预期。芝加哥期权交易所(CBOE) 股票看跌/看涨比率的计算方法是将芝加哥期权交易所股票看跌期权的交易量除以芝加哥期权交易所股票看涨期权的交易量。看跌/看涨期权比率上升，意味着股票交易员买入的看跌期权多于看涨期权，表明市场人气看跌，而看跌/看涨比率下降则被视为市场人气上涨。
</p>
<p>
  我们从Quandl导入每日波动率数据。CBOE提供了从2006年11月1日到现在的成交量看跌/看涨比率数据，因此我们从<a href="http://www.cboe.com/data/historical-options-data/volume-put-call-ratios">CBOE</a>导入自定义数据。
</p>
<div class="section-example-container">
<pre class="python">
class SentimentAndStyleRotationAlgorithm(QCAlgorithm):
  def Initialize(self):
      self.SetStartDate(2010, 1, 1)
      self.SetEndDate(2018, 7, 1)
      self.SetCash(100000)
      self.AddData(QuandlVix, "CBOE/VIX", Resolution.Daily)
      self.AddData(CBOE, "PutCallRatio", Resolution.Daily)

class QuandlVix(PythonQuandl):
    '''Quandl VIX data class'''
    def __init__(self):
        self.ValueColumnName = "VIX Close"

class CBOE(PythonData):
    '''Cboe Equity Volume Put/Call Ratios (11-01-2006 to present) Custom Data Class'''
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/equitypc.csv", SubscriptionTransportMedium.RemoteFile)

    def Reader(self, config, line, date, isLiveMode):
        if not (line.strip() and line[0].isdigit()): return None
        index = CBOE()
        index.Symbol = config.Symbol

        try:
            # 示例文件格式：
            # 日期        看涨      看跌       合计      看跌/看涨比率
            # 11/1/06    976510    623929    1600439    0.64
            data = line.split(',')
            index.Time = datetime.strptime(data[0], "%m/%d/%Y").strftime("%Y-%m-%d")
            index.Value = Decimal(data[4])

        except ValueError:
                return None

        return index
</pre>
</div>
<h4>股票增长和价值的衡量</h4>
<p>
  纽交所和纳斯达克的所有股票都被用作投资集合。在<code>CoarseSelectionFunction</code>中，我们剔除了没有基本数据的基金。在<code>FineSelectionFunction</code>中，股票根据市值大小被分成十等分。我们的算法只使用前百分之三十来避免小型非流动性股票的潜在问题。
</p>
<div class="section-example-container">
<pre class="python">
def FineSelectionFunction(self, fine):
    if self.month_start:
        self.selection = True

        fine = [i for i in fine if i.EarningReports.BasicAverageShares.ThreeMonths>0
                                and i.EarningReports.BasicEPS.TwelveMonths>0
                                and i.ValuationRatios.PERatio>0
                                and i.ValuationRatios.PBRatio>0]
        # 计算市场价值并将“市值”属性添加到精细集合对象中
        for i in fine:
            i.MarketCap = float(i.EarningReports.BasicAverageShares.ThreeMonths * (i.EarningReports.BasicEPS.TwelveMonths*i.ValuationRatios.PERatio))
        # 根据市值对精细对象分类
        sotrted_market_cap = sorted(fine, key = lambda x:x.MarketCap, reverse=True)
        decile_top1 = sotrted_market_cap[:floor(len(sotrted_market_cap)/10)]
        decile_top2 = sotrted_market_cap[floor(len(sotrted_market_cap)/10):floor(len(sotrted_market_cap)*2/10)]
        decile_top3 = sotrted_market_cap[floor(len(sotrted_market_cap)*2/10):floor(len(sotrted_market_cap)*3/10)]
</pre>
</div>
<p>
  在接下来的步骤中，我们根据市净率将十等分中的每一份再细分为五个投资组合。对于前百分之三十的股票，价值型投资组合由市净率最低的五分之一公司组成，而成长型投资组合则由市净率最高的股票组成。
</p>
<div class="section-example-container">
<pre class="python">
sorted_PB1 = sorted(decile_top1, key = lambda x: x.ValuationRatios.PBRatio)
sorted_PB2 = sorted(decile_top2, key = lambda x: x.ValuationRatios.PBRatio)
sorted_PB3 = sorted(decile_top3, key = lambda x: x.ValuationRatios.PBRatio)
# 价值型投资组合由市净率最低的五分之一公司组成
PB_bottom1 = sorted_PB1[:floor(len(decile_top1)/5)]
PB_bottom2 = sorted_PB2[:floor(len(decile_top2)/5)]
PB_bottom3 = sorted_PB3[:floor(len(decile_top3)/5)]
self.value_portfolio = [i.Symbol for i in PB_bottom1 + PB_bottom2 + PB_bottom3]
# 成长型投资组合由市净率最高的五分之一公司组成
PB_top1 = sorted_PB1[-floor(len(decile_top1)/5):]
PB_top2 = sorted_PB2[-floor(len(decile_top2)/5):]
PB_top3 = sorted_PB3[-floor(len(decile_top3)/5):]
self.growth_portfolio = [i.Symbol for i in PB_top1 + PB_top2 + PB_top3]
</pre>
</div>

<h4>投资者情绪和股票风格之间的关系</h4>
<p>
  根据Lee和Song的研究论文《<a href="http://papers.ssrn.com/sol3/papers.cfm?abstract_id=410185">When Do Value Stocks Outperform Growth Stocks?: Investor Sentiment and Equity Style Rotation Strategies</a>》，当芝加哥期权交易所股票看跌/看涨比率相对较低，并且波动率指数相对较高时，价值型股票的表现往往优于成长型股票。当看跌/看涨比率和波动率指数均较高时，价值组合的表现明显要逊于成长型投资组合。要将每日看跌/看涨比率和波动率数据转换为月度数值，我们取最近一个月和前六个月的平均值。
</p>
<p>
  如果最近芝加哥期权交易所的月平均看跌/看涨比率低于6个月平均水平，而波动率指数(VIX)的一个月平均水平高于6个月平均水平，那么该算法就会做多由排名前百分之三十价值股(市净率最低的五分之一)组成的平均加权投资组合。如果最近芝加哥期权交易所的月平均看跌/看涨比率和VIX指数均高于6个月平均水平，该算法就会做空价值股。否则，该算法既做多价值型股票，也做多成长型股票。持仓期为三个月，投资组合每三个月重新平衡一次。
</P>
<div class="section-example-container">
<pre class="python">
stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
for i in stocks_invested:
    if i not in self.value_portfolio+self.growth_portfolio:
        self.Liquidate(i)

if self.vix_SMA_1.Current.Value > self.vix_SMA_6.Current.Value:
    if self.PCRatio_SMA_1.Current.Value < self.PCRatio_SMA_6.Current.Value:
        long_weight = 1/len(self.value_portfolio)
        for long in self.value_portfolio:
            self.SetHoldings(long, long_weight)
    elif self.PCRatio_SMA_1.Current.Value > self.PCRatio_SMA_6.Current.Value:
        short_weight = 1/len(self.value_portfolio)
        for short in self.value_portfolio:
            self.SetHoldings(short, -short_weight)
else:
    long_weight = 1/len(self.value_portfolio+self.growth_portfolio)
    for long in self.value_portfolio+self.growth_portfolio:
        self.SetHoldings(long, long_weight)
</pre>
</div>
